#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/device.h>
#include <sys/queue.h>
 
#include <pmon.h>

/*
 *  * I/O macros.
 *   */
#define outb(a,v)   (*(volatile unsigned char*)(a) = (v))
#define out8(a,v)   (*(volatile unsigned char*)(a) = (v))
#define outw(a,v)   (*(volatile unsigned short*)(a) = (v))
#define out16(a,v)  outw(a,v)
#define outl(a,v)   (*(volatile unsigned int*)(a) = (v))
#define out32(a,v)  outl(a,v)
#define inb(a)      (*(volatile unsigned char*)(a))
#define in8(a)      (*(volatile unsigned char*)(a))
#define inw(a)      (*(volatile unsigned short*)(a))
#define in16(a)     inw(a)
#define inl(a)      (*(volatile unsigned int*)(a))
#define in32(a)     inl(a)

static unsigned int base = 0xbfd00000;
/*
 *  *  List known devices.
 *   */
static void w83627_write(int dev,int addr,int data)
{
	/*enter*/
	outb(base + 0x2e,0x87);
	outb(base + 0x2e,0x87);
	/*select logic dev reg */
	outb(base + 0x2e,0x7);
	outb(base + 0x2f,dev);
	/*access reg */
	outb(base + 0x2e,addr);
	outb(base + 0x2f,data);
/*exit*/
	outb(base + 0x2e,0xaa);
	outb(base + 0x2e,0xaa);
}

static int w83627_read(int dev,int addr)
{
		int data;
		/*enter*/
		outb(base + 0x2e,0x87);
		outb(base + 0x2e,0x87);
		/*select logic dev reg */
		outb(base + 0x2e,0x7);
		outb(base + 0x2f,dev);
		/*access reg */
		outb(base + 0x2e,addr);
		data=inb(base + 0x2f);
		/*exit*/
		outb(base + 0x2e,0xaa);
		outb(base + 0x2e,0xaa);
		return data;
}

static void LPC_test(void)
{
	int device_id, revision;

	printf("base = 0x%x\n", base);	
	outb(base + 0x2e, 0x87);
	outb(base + 0x2e, 0x87);

	outb(base + 0x2e, 0x20);
	device_id = inb(base + 0x2f);
	printf("device_id = 0x%x\n", device_id);
	
	outb(base + 0x2e, 0x21);
	revision = inb(base + 0x2f);
	printf("revision = 0x%x\n", revision);
}
int cmd_tangyt  __P((int, char *[]));

int cmd_tangyt(int ac, char * av[])
{
	extern int optind;
	static int count = 0;
	int opt_i = 0;
	int opt_k = 0;
	int dev, addr ,data;
	int a1 = 0;
	int a2 = 0;
	char c;
	int oldbase, status;
	
	optind = 0;
	oldbase = base;
	while((c = getopt(ac, av, "bwrtas")) != EOF)
	{
		switch(c)
		{
			case 'b':
				printf("old base = 0x%x\n", oldbase);
				status = get_rsa(&base, av[optind++]);
				if(status == -1)
				{
					base = oldbase;
				}	
				printf("new base = 0x%x\n", base);
				break;
			case 't':
				LPC_test();	
				break;
			case 'a':
				printf("optind = %d\n", optind);
				if(!get_rsa(&a1, av[optind++]))
					return -1;
				printf("optind = %d\n", optind);
				if(!get_rsa(&a2, av[optind++]))
					return -1;
				printf("add: %d + %d = %d\n", a1, a2, a1+a2);
				break;
			case 's':
				printf("optind = %d\n", optind);
				if(!get_rsa(&a1, av[optind++]))
					return -1;
				if(!get_rsa(&a2, av[optind++]))
					return -1;
				printf("add: %d - %d = %d\n", a1, a2, a1-a2);
				break;
			case 'w':
				if(!get_rsa(&dev, av[optind++]))
					return -1;
				if(!get_rsa(&addr, av[optind++]))
					return -1;
				if(!get_rsa(&data, av[optind++]))
					return -1;
				w83627_write(dev, addr, data);
				printf("dev = 0x%x, addr = 0x%x, data = 0x%x\n", dev, addr ,data);
				break;
			case 'r':
				if(!get_rsa(&dev, av[optind++]))
					return -1;
				if(!get_rsa(&addr, av[optind++]))
					return -1;
				data = w83627_read(dev, addr);
				printf("dev = 0x%x, addr = 0x%x, data = 0x%x\n", dev, addr ,data);
				break;
				
			default:
				return -1;
		}
	}
	return 1;
}

/*
 *  *  Command table registration
 *   *  ==========================
 *    */
 
const Optdesc cmd_tangyt_opts[] = {
    { "-b", "set a new base:  superio -b newbase " },
    { "-w", "superio -w dev addr data " },
    { "-r", "superio -r dev addr " },
    { "-r", "test the superio:  superio -t " },
    { 0 }
};
 
static const Cmd Cmds[] =
{
	{"tangyt"},/*the first element do not work, but it must be exist*/
    {"superio",   "[-ikas]",
    cmd_tangyt_opts,
    "operation about superio",
    cmd_tangyt, 1, 10,
    0},
    {0, 0}
};
 
static void init_cmd __P((void)) __attribute__ ((constructor));
 
void
init_cmd()
{
    cmdlist_expand(Cmds, 1);
}
 
